package org.jetnuke.modules.pictures;

import org.apache.log4j.Logger;

import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.GregorianCalendar;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.jforum.ActionServletRequest;
import net.jforum.JForumExecutionContext;
import net.jforum.util.legacy.commons.fileupload.FileItem;
import net.jforum.util.preferences.ConfigKeys;
import net.jforum.util.preferences.SystemGlobals;

import org.apache.velocity.VelocityContext;
import org.jetnuke.common.ActionForward;
import org.jetnuke.common.IAction;
import org.jetnuke.common.IAdminInfo;
import org.jetnuke.common.IModuleInfo;
import org.jetnuke.common.IUserInfo;
import org.jetnuke.dao.DataAccessDriver;
import org.jetnuke.dao.PictureDAO;
import org.jetnuke.entities.Picture;
import org.jetnuke.util.JetUtil;
import org.jetnuke.util.StringUtils;

import com.sun.jimi.core.InvalidOptionException;
import com.sun.jimi.core.Jimi;
import com.sun.jimi.core.JimiException;
import com.sun.jimi.core.JimiImage;
import com.sun.jimi.core.encoder.jpg.JPGEncoder;
import com.sun.jimi.core.encoder.jpg.JPGEncoderFactory;
import com.sun.jimi.core.filters.AspectReplicateScaleFilter;
import com.sun.jimi.core.filters.Smooth;
import com.sun.jimi.core.raster.JimiRasterImage;

public class UploadFiles implements IAction {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(UploadFiles.class);

	public ActionForward exec(HttpServletRequest request,
			HttpServletResponse response, VelocityContext vc, IModuleInfo info,
			String op, IUserInfo ui, IAdminInfo ai) throws Exception {
		if (logger.isDebugEnabled()) {
			logger
					.debug("exec(HttpServletRequest, HttpServletResponse, VelocityContext, IModuleInfo, String, IUserInfo, IAdminInfo) - start"); //$NON-NLS-1$
		}

		if (ui == null || ui.getID() < 2)
			return null;
		String ip = request.getRemoteAddr();
		String initPath = SystemGlobals
				.getValue(ConfigKeys.ATTACHMENTS_STORE_DIR)
				+ "/pictures/" + ui.getID() + "/";
		// String path = sc.getRealPath(initPath);
		File pathDir = new File(initPath);
		if (!pathDir.exists()) {
			pathDir.mkdirs();
		}

		// JForum.DataHolder dataHolder =
		// (JForum.DataHolder)JForumBaseServlet.localData.get();
		ActionServletRequest asr = JForumExecutionContext.getRequest();
		int album = Integer.parseInt(asr.getParameter("album"));
		FileItem file1 = (FileItem) asr.getObjectParameter("file1");
		FileItem file2 = (FileItem) asr.getObjectParameter("file2");
		FileItem file3 = (FileItem) asr.getObjectParameter("file3");
		FileItem file4 = (FileItem) asr.getObjectParameter("file4");
		FileItem file5 = (FileItem) asr.getObjectParameter("file5");
		if (file1 != null) {
			manageFile(file1, pathDir, ui, ip, album);
		}
		if (file2 != null) {
			manageFile(file2, pathDir, ui, ip, album);
		}
		if (file3 != null) {
			manageFile(file3, pathDir, ui, ip, album);
		}
		if (file4 != null) {
			manageFile(file4, pathDir, ui, ip, album);
		}
		if (file5 != null) {
			manageFile(file5, pathDir, ui, ip, album);
		}

		JetUtil.redirect(vc, response, request.getContextPath()
				+ "/do/pictures/show_album?aid=" + album);

		if (logger.isDebugEnabled()) {
			logger
					.debug("exec(HttpServletRequest, HttpServletResponse, VelocityContext, IModuleInfo, String, IUserInfo, IAdminInfo) - end"); //$NON-NLS-1$
		}
		return null;
	}

	private void manageFile(FileItem ff, File pathDir, IUserInfo ui, String ip,
			int album) throws Exception {
		if (logger.isDebugEnabled()) {
			logger
					.debug("manageFile(FileItem, File, IUserInfo, String, int) - start"); //$NON-NLS-1$
		}

		// long fileSize=ff.getSize();
		// long resourcesSize=getResourcesSize(0,pathDir);

		String realName = ff.getName();
		String simplifiedName = StringUtils.getSimpleFileName(realName);
		if (simplifiedName.toLowerCase().endsWith(".zip")) {
			ZipInputStream in = new ZipInputStream(ff.getInputStream());
			ZipEntry entry = null;

			while ((entry = in.getNextEntry()) != null) {
				ByteArrayOutputStream baosEntry = new ByteArrayOutputStream(
						(int) entry.getSize());
				byte[] buf = new byte[2048];
				int len = 0;
				while ((len = in.read(buf)) > 0) {
					baosEntry.write(buf, 0, len);
				}

				baosEntry.close();
				if (baosEntry.size() > 0) {
					try {
						JimiRasterImage img = Jimi.getRasterImage(
								new ByteArrayInputStream(baosEntry
										.toByteArray()), Jimi.SYNCHRONOUS
										| Jimi.VIRTUAL_MEMORY);

						manageImage(pathDir, ui, ip, StringUtils
								.getSimpleFileName(entry.getName()), baosEntry
								.size(), img, baosEntry, album);

					} catch (Throwable t) {
						logger
								.error(
										"manageFile(FileItem, File, IUserInfo, String, int)", t); //$NON-NLS-1$

						t.printStackTrace();
					}
				}

			}
			in.close();
		} else {

			int size = (int) ff.getSize();

			ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
			baos.write(ff.get());
			JimiRasterImage img = Jimi.getRasterImage(new ByteArrayInputStream(
					baos.toByteArray()), Jimi.SYNCHRONOUS);
			manageImage(pathDir, ui, ip, simplifiedName, size, img, baos, album);

		}

		if (logger.isDebugEnabled()) {
			logger
					.debug("manageFile(FileItem, File, IUserInfo, String, int) - end"); //$NON-NLS-1$
		}
	}

	private void manageImage(File pathDir, IUserInfo ui, String ip,
			String simplifiedName, int size, JimiRasterImage img,
			ByteArrayOutputStream baos, int album)
			throws FileNotFoundException, IOException, JimiException,
			InvalidOptionException, Exception {
		if (logger.isDebugEnabled()) {
			logger
					.debug("manageImage(File, IUserInfo, String, String, int, JimiRasterImage, ByteArrayOutputStream, int) - start"); //$NON-NLS-1$
		}

		String mimeType = "";

		String extension = simplifiedName.toLowerCase();
		String name_no_extension = extension;
		int last = extension.lastIndexOf(".");
		if (last != -1) {
			extension = extension.substring(last + 1);
			name_no_extension = name_no_extension.substring(0, last);
		}
		mimeType = decodeMimeType(extension);

		int total_size = size;
		int height = img.getHeight();
		int width = img.getWidth();
		int max = Math.max(height, width);
		File f = new File(pathDir, simplifiedName);
		OutputStream outputStream = new BufferedOutputStream(
				new FileOutputStream(f));
		baos.writeTo(outputStream);
		outputStream.flush();
		outputStream.close();
		Picture picture = new Picture();
		picture.setTITLE(name_no_extension);
		if (max > 100) {

			ImageFilter smoothedFilter = new Smooth(img.getImageProducer(), 1);

			FilteredImageSource smoothedSource = new FilteredImageSource(img
					.getImageProducer(), smoothedFilter);
			ImageFilter scaleFilter = new AspectReplicateScaleFilter(width
					* 100 / max, height * 100 / max);
			FilteredImageSource scaledSource = new FilteredImageSource(
					smoothedSource, scaleFilter);
			JimiImage scaledImage = Jimi.createRasterImage(scaledSource);

			int extIndex = simplifiedName.lastIndexOf(".");
			String thumbName = "thumb_";
			if (extIndex > -1) {
				thumbName += simplifiedName.substring(0, extIndex);
			} else {
				thumbName += simplifiedName;
			}
			thumbName = thumbName + ".jpg";
			JPGEncoderFactory factory = new JPGEncoderFactory();
			JPGEncoder encoder = (JPGEncoder) factory.createEncoder();
			encoder.setProperty("quality", new Integer(70));
			File fthumb = new File(pathDir, thumbName);
			BufferedOutputStream out = new BufferedOutputStream(
					new FileOutputStream(fthumb));
			encoder.encodeImage(scaledImage, out);
			out.close();
			total_size = total_size + (int) fthumb.length();
			picture.setTHUMBNAME(thumbName);
			picture.setTHUMBMIMETYPE("image/jpeg");
		}
		if (max > 400) {
			ImageFilter smoothedFilter = new Smooth(img.getImageProducer(), 1);

			FilteredImageSource smoothedSource = new FilteredImageSource(img
					.getImageProducer(), smoothedFilter);
			ImageFilter scaleFilter = new AspectReplicateScaleFilter(height
					* 400 / max, width * 400 / max);
			FilteredImageSource scaledSource = new FilteredImageSource(
					smoothedSource, scaleFilter);
			JimiImage scaledImage = Jimi.createRasterImage(scaledSource);

			int extIndex = simplifiedName.lastIndexOf(".");
			String mediumName = "medium_";
			if (extIndex > -1) {
				mediumName += simplifiedName.substring(0, extIndex);
			} else {
				mediumName += simplifiedName;
			}
			mediumName = mediumName + ".jpg";
			JPGEncoderFactory factory = new JPGEncoderFactory();
			JPGEncoder encoder = (JPGEncoder) factory.createEncoder();
			encoder.setProperty("quality", new Integer(70));
			File fmedium = new File(pathDir, mediumName);
			BufferedOutputStream out = new BufferedOutputStream(
					new FileOutputStream(fmedium));
			encoder.encodeImage(scaledImage, out);
			out.close();
			total_size = total_size + (int) fmedium.length();
			picture.setMEDIUMNAME(mediumName);
			picture.setMEDIUMMIMETYPE("image/jpeg");
		}

		PictureDAO pd = DataAccessDriver.getInst().newPictureDAO();

		picture.setUID(ui.getID());
		picture.setAPPROVED("YES");
		picture.setCAPTION("");
		picture.setFILENAME(simplifiedName);
		picture.setFILEPATH("");
		picture.setFILESIZE(size);
		picture.setKEYWORDS("");
		picture.setMTIME(new GregorianCalendar().getTime());
		picture.setPHEIGHT(height);
		picture.setPIC_RAW_IP(ip);
		picture.setPWIDTH(width);

		picture.setTOTAL_SIZE(total_size);
		picture.setMIMETYPE(mimeType);
		picture.setAID(album);
		pd.addNew(picture);

		if (logger.isDebugEnabled()) {
			logger
					.debug("manageImage(File, IUserInfo, String, String, int, JimiRasterImage, ByteArrayOutputStream, int) - end"); //$NON-NLS-1$
		}
	}

	private String decodeMimeType(String ext) {
		if (logger.isDebugEnabled()) {
			logger.debug("decodeMimeType(String) - start"); //$NON-NLS-1$
		}

		if ("bmp".equals(ext))
			return "image/bmp";
		if ("gif".equals(ext))
			return "image/gif";
		if ("jpe".equals(ext) || "jpg".equals(ext) || "jpeg".equals(ext))
			return "image/jpeg";
		if ("png".equals(ext))
			return "image/png";
		if ("tif".equals(ext) || "tiff".equals(ext))
			return "image/tiff";
		if ("ico".equals(ext))
			return "image/x-icon";

		if (logger.isDebugEnabled()) {
			logger.debug("decodeMimeType(String) - end"); //$NON-NLS-1$
		}
		return "";
	}

	public static long getResourcesSize(long initSize, File pathDir) {
		if (logger.isDebugEnabled()) {
			logger.debug("getResourcesSize(long, File) - start"); //$NON-NLS-1$
		}

		File f[] = pathDir.listFiles();
		long ret = initSize;
		for (int i = 0; i < f.length; i++) {
			if (f[i].isFile()) {
				ret = ret + f[i].length();
			} else {
				ret = getResourcesSize(ret, f[i]);
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("getResourcesSize(long, File) - end"); //$NON-NLS-1$
		}
		return ret;
	}

}
